package com.geecity.flowable.flowabledemo.service.impl;

import cn.hutool.core.util.StrUtil;

import com.geecity.flowable.flowabledemo.entity.R;
import com.geecity.flowable.flowabledemo.mapper.DispatchMapper;
import com.geecity.flowable.flowabledemo.service.DispatchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;


/**
 * @author yuanDing
 * @version 1.0
 * @date 2025-07-09 10:01
 */

@Service
public class DispatchServiceImpl implements DispatchService {

    private static final Logger log = LoggerFactory.getLogger(DispatchServiceImpl.class);

    @Autowired
    private DispatchMapper dispatchMapper;


    /**
     * 程序包分发临时存放路径
     */
    @Value("${systemEnvironment.dispatchTempPath:dispatchTemp}")
    private String dispatchTempPath;


    /**
     * 原始程序包临时存放路径
     */
    @Value("${dispatch.upgradePackageFolderPath}")
    private String upgradePackageFolderPath;



    @Value("${dispatch.web-page.old-version-folder-name}")
    private String oldVersionFolderName;

    @Value("${dispatch.local-ip}")
    private String localIp;



    /**
     * SSH连接超时时间（秒）
     */
    private static final int SSH_TIMEOUT = 10;

    public R dispatch(String cangKuUuid, MultipartFile file) {
        log.info("开始处理文件派发请求 - 仓库UUID: {}, 文件名: {}, 文件大小: {}",
                cangKuUuid, file.getOriginalFilename(), file.getSize());

        // 获取待分发程序服务器信息
        List<Map<String, Object>> serverList = dispatchMapper.selectServerMessage(cangKuUuid);
        log.info("查询到服务器信息: {}", serverList);

        if (serverList.isEmpty()) {
            log.error("未找到服务器配置信息 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置服务器信息！");
        }

        Map<String, Object> serverMap = serverList.get(0);

        Object serverIpMessage = serverMap.get("chengxufuwuqiValue");
        if (StrUtil.isBlankIfStr(serverIpMessage)) {
            log.error("服务器IP地址为空 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置分发服务器ip地址！");
        }

        Object programParentFolderMessage = serverMap.get("chengxubushuwenjianjia");
        if (StrUtil.isBlankIfStr(programParentFolderMessage)) {
            log.error("程序存放路径为空 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置分发服务器程序存放路径！");
        }

        String serverIp = serverIpMessage.toString().split(":")[0];
        String programParentFolderPath = programParentFolderMessage.toString();
        log.info("解析服务器信息 - IP: {}, 程序路径: {}", serverIp, programParentFolderPath);

        // 先检查SSH连接是否可用
        if (!checkSshConnection(serverIp)) {
            log.error("SSH连接检查失败 - 服务器IP: {}", serverIp);
            return R.fail("无法连接到目标服务器，请检查SSH免密配置是否正确");
        }

        /**
         * 使用scp方式分发程序，服务器之间已经互信
         * 1、将文件写入临时文件夹，临时文件夹为 dispatchTempPath
         * 2、使用scp命令分发文件到服务器，目标服务器ip：serverIp，目标服务器程序存放路径：programParentFolderPath
         * 3、分发完成删除临时文件
         */

        File tempDir = new File(dispatchTempPath);
        if (!tempDir.exists()) {
            log.info("创建临时目录: {}", dispatchTempPath);
            if (!tempDir.mkdirs()) {
                log.error("创建临时目录失败: {}", dispatchTempPath);
                return R.fail("创建临时目录失败，请检查权限和磁盘空间");
            }
        }

        if (file == null || file.isEmpty()) {
            log.error("上传的文件为空");
            return R.fail("上传的文件不能为空");
        }

        // 创建临时文件
        String originalFilename = file.getOriginalFilename();
        if (StrUtil.isBlank(originalFilename)) {
            log.error("文件名为空");
            return R.fail("文件名不能为空");
        }

        Path tempFilePath = Paths.get(dispatchTempPath, originalFilename);
        log.info("开始写入临时文件: {}", tempFilePath);

        try {
            // 将上传的文件写入临时目录，如果文件存在则替换
            Files.copy(file.getInputStream(), tempFilePath, java.nio.file.StandardCopyOption.REPLACE_EXISTING);
            log.info("文件写入成功: {} (大小: {} bytes)", tempFilePath, Files.size(tempFilePath));

            // 检查文件是否成功写入
            if (!Files.exists(tempFilePath)) {
                log.error("文件写入失败，临时文件不存在: {}", tempFilePath);
                return R.fail("文件写入失败，请重试");
            }

            // 处理路径分隔符，确保使用正斜杠
            String normalizedTempPath = tempFilePath.toString().replace('\\', '/');
            String normalizedTargetPath = programParentFolderPath.endsWith("/") ?
                    programParentFolderPath : programParentFolderPath + "/";

            // 构建scp命令，添加超时和禁用密码提示参数
            String scpCommand = String.format("scp -o BatchMode=yes -o ConnectTimeout=%d %s %s:%s",
                    SSH_TIMEOUT,
                    normalizedTempPath,
                    serverIp,
                    normalizedTargetPath);

            log.info("开始执行SCP命令: {}", scpCommand);

            // 使用线程池执行命令，添加超时控制
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<Process> future = executor.submit(() -> Runtime.getRuntime().exec(scpCommand));

            Process process = null;
            try {
                process = future.get(SSH_TIMEOUT, TimeUnit.SECONDS);

                // 读取标准输出
                BufferedReader inputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                StringBuilder outputMessage = new StringBuilder();
                String line;
                while ((line = inputReader.readLine()) != null) {
                    outputMessage.append(line).append("\n");
                }
                if (outputMessage.length() > 0) {
                    log.info("SCP命令标准输出: {}", outputMessage);
                }

                // 等待命令执行完成，添加超时
                if (!process.waitFor(SSH_TIMEOUT, TimeUnit.SECONDS)) {
                    log.error("SCP命令执行超时");
                    process.destroyForcibly();
                    return R.fail("程序分发超时，请检查网络连接");
                }

                int exitCode = process.exitValue();
                log.info("SCP命令执行完成，退出码: {}", exitCode);

                if (exitCode != 0) {
                    // 获取错误输出流
                    BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                    StringBuilder errorMessage = new StringBuilder();
                    while ((line = errorReader.readLine()) != null) {
                        errorMessage.append(line).append("\n");
                    }
                    String errorMsg = errorMessage.toString().trim();
                    log.error("SCP命令执行失败: {}", errorMsg);

                    // 检查具体错误类型
                    if (errorMsg.contains("Host key verification failed")) {
                        return R.fail("程序分发失败：SSH主机验证失败，请确保目标服务器的SSH密钥已添加到known_hosts");
                    } else if (errorMsg.contains("lost connection")) {
                        return R.fail("程序分发失败：与目标服务器的连接丢失，请检查网络连接");
                    } else {
                        return R.fail("程序分发失败，SCP命令执行异常：" + errorMsg);
                    }
                }

                log.info("文件成功传输到目标服务器: {}", programParentFolderPath);
                return R.ok("程序分发成功");

            } catch (TimeoutException e) {
                log.error("SCP命令执行超时", e);
                if (process != null) {
                    process.destroyForcibly();
                }
                return R.fail("程序分发超时，请检查网络连接");
            } catch (Exception e) {
                log.error("SCP命令执行异常", e);
                if (process != null) {
                    process.destroyForcibly();
                }
                return R.fail("程序分发失败：" + e.getMessage());
            } finally {
                executor.shutdownNow();
                // 清理临时文件
                try {
                    log.info("开始清理临时文件: {}", tempFilePath);
                    Files.deleteIfExists(tempFilePath);
                    log.info("临时文件清理完成");
                } catch (IOException e) {
                    // 记录删除临时文件失败，但不影响主流程
                    log.warn("清理临时文件失败: {}", e.getMessage());
                }
            }

        } catch (Exception e) {
            log.error("文件派发过程发生异常", e);
            return R.fail("程序分发失败：" + e.getMessage());
        }
    }

    /**
     * 服务部署
     * @param cangKuUuid
     * @param jarName
     * @param response 用于流式输出日志
     */
    @Override
    public void deployment(String cangKuUuid, String jarName, HttpServletResponse response) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<?> future = null;

        try {
            response.setContentType("text/event-stream");
            response.setCharacterEncoding("UTF-8");
            PrintWriter writer = response.getWriter();

            // 发送日志到前端的辅助方法
            BiConsumer<String, String> sendLog = (type, message) -> {
                try {
                    Map<String, String> logMap = new HashMap<>();
                    logMap.put("type", type);
                    logMap.put("message", message);
                    writer.write("data: " + new ObjectMapper().writeValueAsString(logMap) + "\n\n");
                    writer.flush();
                } catch (Exception e) {
                    log.error("发送日志失败", e);
                }
            };

            // 将部署任务提交到执行器
            future = executor.submit(() -> {
                try {
                    log.info("开始处理服务部署请求 - 仓库UUID: {}, 服务包名: {}", cangKuUuid, jarName);
                    sendLog.accept("INFO", "开始部署服务: " + jarName);

                    // 获取部署服务器信息
                    List<Map<String, Object>> serverList = dispatchMapper.selectServerMessage(cangKuUuid);
                    if (serverList.isEmpty()) {
                        sendLog.accept("ERROR", "未找到服务器配置信息");
                        return;
                    }

                    Map<String, Object> serverMap = serverList.get(0);
                    Object serverIpMessage = serverMap.get("chengxufuwuqiValue");
                    Object programParentFolderMessage = serverMap.get("chengxubushuwenjianjia");

                    if (StrUtil.isBlankIfStr(serverIpMessage)) {
                        sendLog.accept("ERROR", "未配置服务器IP地址");
                        return;
                    }

                    if (StrUtil.isBlankIfStr(programParentFolderMessage)) {
                        sendLog.accept("ERROR", "未配置程序存放路径");
                        return;
                    }

                    String serverIp = serverIpMessage.toString().split(":")[0];
                    String programParentFolderPath = programParentFolderMessage.toString();
                    sendLog.accept("INFO", "服务器信息: " + serverIp + ", 部署路径: " + programParentFolderPath);

                    // 检查文件是否存在
                    String[] checkCmd = new String[]{
                            "ssh",
                            serverIp,
                            "[ -f " + programParentFolderPath + jarName + " ] && echo 'exists'"
                    };

                    Process checkProcess = new ProcessBuilder(checkCmd).start();
                    String checkResult = new BufferedReader(new InputStreamReader(checkProcess.getInputStream())).lines()
                            .collect(Collectors.joining("\n"));

                    if (!"exists".equals(checkResult.trim())) {
                        sendLog.accept("ERROR", "待部署的程序文件不存在：" + programParentFolderPath + jarName);
                        return;
                    }
                    sendLog.accept("INFO", "文件存在检查通过");

                    // 检查是否有正在运行的程序
                    String[] findCmd = new String[]{
                            "ssh",
                            serverIp,
                            "find " + programParentFolderPath + " -maxdepth 1 -type f \\( -name '*.jar' -o -name '*.war' \\)"
                    };

                    Process findProcess = new ProcessBuilder(findCmd).start();
                    BufferedReader findReader = new BufferedReader(new InputStreamReader(findProcess.getInputStream()));
                    String findLine;
                    boolean hasRunningProcess = false;
                    StringBuilder runningProcesses = new StringBuilder();

                    while ((findLine = findReader.readLine()) != null) {
                        String fileName = findLine.substring(findLine.lastIndexOf('/') + 1);
                        // 检查每个文件是否正在运行
                        String[] psCmd = new String[]{
                                "ssh",
                                serverIp,
                                "ps -ef | grep " + fileName + " | grep -v grep"
                        };

                        Process psProcess = new ProcessBuilder(psCmd).start();
                        BufferedReader psReader = new BufferedReader(new InputStreamReader(psProcess.getInputStream()));
                        String psLine;
                        while ((psLine = psReader.readLine()) != null) {
                            hasRunningProcess = true;
                            runningProcesses.append(fileName).append("\n");
                            break;
                        }
                        psProcess.waitFor();
                    }

                    findProcess.waitFor();

                    if (hasRunningProcess) {
                        sendLog.accept("ERROR", "当前项目目录下存在正在运行的程序：\n" + runningProcesses.toString() + "请先停止运行中的程序");
                        writer.close(); // 关闭流
                        return;
                    }

                    sendLog.accept("INFO", "进程检查通过，无运行中的服务");

                    // 执行启动脚本
                    String[] startupCmd = new String[]{
                            "ssh",
                            serverIp,
                            "cd " + programParentFolderPath + " && ./startup.sh " + jarName + " 2>&1"
                    };

                    sendLog.accept("INFO", "开始执行启动命令");
                    Process startupProcess = new ProcessBuilder(startupCmd).start();

                    // 实时读取并发送启动输出
                    BufferedReader startupReader = new BufferedReader(new InputStreamReader(startupProcess.getInputStream()));
                    String line;
                    long startTime = System.currentTimeMillis();
                    long timeout = 180000; // 3分钟超时

                    try {
                        while ((line = startupReader.readLine()) != null) {
                            sendLog.accept("LOG", line);
                            if (line.contains("启动成功")) {
                                sendLog.accept("SUCCESS", "服务启动成功");
                                writer.close(); // 关闭流
                                return;
                            }

                            // 检查是否超时
                            if (System.currentTimeMillis() - startTime > timeout) {
                                sendLog.accept("ERROR", "启动超时，请手动检查服务状态");
                                startupProcess.destroy(); // 结束进程
                                writer.close(); // 关闭流
                                return;
                            }
                        }

                        // 给进程一个短暂的时间完成
                        if (startupProcess.waitFor(10, TimeUnit.SECONDS)) {
                            int exitCode = startupProcess.exitValue();
                            if (exitCode != 0) {
                                sendLog.accept("ERROR", "启动脚本执行失败，退出码：" + exitCode);
                            } else {
                                sendLog.accept("SUCCESS", "启动脚本执行完成");
                            }
                        } else {
                            sendLog.accept("ERROR", "启动脚本执行时间过长，已终止");
                            startupProcess.destroy();
                        }
                    } finally {
                        writer.close(); // 确保流被关闭
                    }

                } catch (Exception e) {
                    log.error("部署过程发生异常", e);
                    sendLog.accept("ERROR", "部署异常：" + e.getMessage());
                }
            });

            // 等待任务完成或超时
            try {
                future.get(180, TimeUnit.SECONDS); // 3分钟超时
            } catch (TimeoutException e) {
                log.error("部署超时", e);
                sendLog.accept("ERROR", "部署操作超时（3分钟），请检查服务状态");
                future.cancel(true); // 尝试取消任务
            } catch (Exception e) {
                log.error("等待部署完成时发生异常", e);
                sendLog.accept("ERROR", "部署异常：" + e.getMessage());
            }

        } catch (Exception e) {
            log.error("部署过程发生异常", e);
            try {
                Map<String, String> errorMap = new HashMap<>();
                errorMap.put("type", "ERROR");
                errorMap.put("message", "部署异常：" + e.getMessage());
                response.getWriter().write("data: " + new ObjectMapper().writeValueAsString(errorMap) + "\n\n");
                response.getWriter().flush();
            } catch (Exception ex) {
                log.error("发送错误信息失败", ex);
            }
        } finally {
            try {
                response.getWriter().close();
            } catch (Exception e) {
                log.error("关闭响应流失败", e);
            }

            // 关闭执行器
            executor.shutdownNow();
            try {
                if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
                    log.warn("执行器未能在5秒内完全关闭");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.error("等待执行器关闭时被中断", e);
            }
        }
    }

    /**
     * 检查SSH连接是否可用
     */
    private boolean checkSshConnection(String serverIp) {
        String checkCommand = String.format("ssh -o BatchMode=yes -o ConnectTimeout=%d %s echo test",
                SSH_TIMEOUT, serverIp);
        try {
            Process process = Runtime.getRuntime().exec(checkCommand);
            return process.waitFor(SSH_TIMEOUT, TimeUnit.SECONDS) && process.exitValue() == 0;
        } catch (Exception e) {
            log.error("SSH连接检查失败", e);
            return false;
        }
    }

    @Override
    public R deploymentMessageList(String cangKuUuid) {
        log.info("开始获取服务列表 - 仓库UUID: {}", cangKuUuid);

        // 获取部署服务器信息
        List<Map<String, Object>> serverList = dispatchMapper.selectServerMessage(cangKuUuid);
        log.info("查询到服务器信息: {}", serverList);

        if (serverList.isEmpty()) {
            String errorMsg = "未找到服务器配置信息，请检查仓库UUID: " + cangKuUuid;
            log.error(errorMsg);
            return R.fail(errorMsg);
        }

        Map<String, Object> serverMap = serverList.get(0);

        Object serverIpMessage = serverMap.get("chengxufuwuqiValue");
        if (StrUtil.isBlankIfStr(serverIpMessage)) {
            String errorMsg = "未配置服务器IP地址，请检查仓库配置";
            log.error(errorMsg);
            return R.fail(errorMsg);
        }

        Object programParentFolderMessage = serverMap.get("chengxubushuwenjianjia");
        if (StrUtil.isBlankIfStr(programParentFolderMessage)) {
            String errorMsg = "未配置程序存放路径，请检查仓库配置";
            log.error(errorMsg);
            return R.fail(errorMsg);
        }

        String serverIp = serverIpMessage.toString().split(":")[0];
        String programParentFolderPath = programParentFolderMessage.toString();
        log.info("解析服务器信息 - IP: {}, 程序路径: {}", serverIp, programParentFolderPath);

        ArrayList<Map<String, String>> serviceList = new ArrayList<>();

        try {
            // 首先检查目录是否存在
// 改进后的命令
            String[] checkDirCmd = new String[]{
                    "ssh",
                    "-o", "StrictHostKeyChecking=no",  // 跳过主机密钥确认
                    "-o", "BatchMode=yes",             // 禁用所有交互提示
                    "-o", "ConnectTimeout=10",         // 连接超时10秒
                    serverIp,
                    // 使用单引号包裹路径，处理特殊字符
                    "[ -d '" + programParentFolderPath.replace("'", "'\\''") + "' ] && echo 'exists' || echo 'not exists'"
            };

            log.info("执行目录检查命令: {}", String.join(" ", checkDirCmd));
            Process checkDirProcess = new ProcessBuilder(checkDirCmd).start();
            BufferedReader checkReader = new BufferedReader(new InputStreamReader(checkDirProcess.getInputStream()));
            String checkResult = checkReader.lines().collect(Collectors.joining("\n"));

            if (!"exists".equals(checkResult.trim())) {
                String errorMsg = String.format("目录不存在或无访问权限: %s，请检查:\n1. 目录是否存在\n2. 目录权限是否正确\n3. SSH连接是否正常",
                        programParentFolderPath);
                log.error(errorMsg);
                return R.fail(errorMsg);
            }

            // 1. 获取目录下的所有jar和war文件
            String[] findCmd = new String[]{
                    "ssh",
                    serverIp,
                    "find " + programParentFolderPath + " -maxdepth 1 -type f \\( -name '*.jar' -o -name '*.war' \\) -printf '%p\t%T@\n'"
            };

            log.info("执行文件查找命令: {}", String.join(" ", findCmd));
            ProcessBuilder processBuilder = new ProcessBuilder(findCmd);
            processBuilder.redirectErrorStream(true); // 合并错误流和标准输出流
            Process findProcess = processBuilder.start();

            // 读取输出
            BufferedReader findReader = new BufferedReader(new InputStreamReader(findProcess.getInputStream()));
            StringBuilder output = new StringBuilder();
            String line;
            while ((line = findReader.readLine()) != null) {
                output.append(line).append("\n");
                // 检查是否是错误信息
                if (line.contains("No such file or directory")) {
                    continue;
                }

                // 解析文件路径和时间戳
                String[] parts = line.split("\t");
                if (parts.length != 2) {
                    log.warn("无效的文件信息格式: {}", line);
                    continue;
                }

                String filePath = parts[0];
                String fileName = filePath.substring(filePath.lastIndexOf('/') + 1);

                // 转换时间戳为可读格式
                try {
                    double timestamp = Double.parseDouble(parts[1]);
                    long lastModified = (long) (timestamp * 1000); // 转换为毫秒
                    String formattedTime = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(lastModified));

                    log.info("找到服务包文件: {}, 最后修改时间: {}", fileName, formattedTime);

                    // 2. 检查每个文件是否正在运行
                    String[] psCmd = new String[]{
                            "ssh",
                            serverIp,
                            "ps -ef | grep " + fileName + " | grep -v grep"
                    };

                    log.debug("执行进程检查命令: {}", String.join(" ", psCmd));
                    ProcessBuilder psBuilder = new ProcessBuilder(psCmd);
                    psBuilder.redirectErrorStream(true);
                    Process psProcess = psBuilder.start();

                    // 读取ps命令输出
                    BufferedReader psReader = new BufferedReader(new InputStreamReader(psProcess.getInputStream()));
                    StringBuilder psOutput = new StringBuilder();
                    String psLine;
                    while ((psLine = psReader.readLine()) != null) {
                        psOutput.append(psLine).append("\n");
                    }

                    Map<String, String> serviceInfo = new HashMap<>();
                    serviceInfo.put("servicePackageName", fileName);
                    serviceInfo.put("lastModified", formattedTime);
                    boolean isRunning = psOutput.toString().trim().length() > 0;
                    serviceInfo.put("serviceStatus", isRunning ? "1" : "0");
                    log.info("服务状态检查 - 服务包: {}, 运行状态: {}", fileName, isRunning ? "运行中" : "已停止");

                    serviceList.add(serviceInfo);

                    // 等待进程结束并检查退出码
                    int psExitCode = psProcess.waitFor();
                    if (psExitCode != 0) {
                        log.warn("进程检查命令退出码非0 - 文件: {}, 退出码: {}, 输出: {}", fileName, psExitCode, psOutput);
                    }
                } catch (NumberFormatException e) {
                    log.warn("解析文件时间戳失败: {}", parts[1], e);
                }
            }

            // 等待find命令结束并检查退出码
            int findExitCode = findProcess.waitFor();
            if (findExitCode != 0) {
                String errorOutput = output.toString().trim();
                String errorMsg = String.format("获取服务列表失败:\n1. 退出码: %d\n2. 错误信息: %s\n请检查服务器连接和目录权限",
                        findExitCode, errorOutput);
                log.error(errorMsg);
                return R.fail(errorMsg);
            }

            if (serviceList.isEmpty()) {
                String message = String.format("目录 %s 中未找到任何服务包文件 (*.jar 或 *.war)", programParentFolderPath);
                log.warn(message);
                return R.ok(serviceList);
            }

            log.info("服务列表获取完成，共找到 {} 个服务", serviceList.size());
            return R.ok(serviceList);

        } catch (Exception e) {
            String errorMsg = String.format("获取服务列表异常:\n1. 错误类型: %s\n2. 错误信息: %s\n请检查服务器连接和配置",
                    e.getClass().getSimpleName(), e.getMessage());
            log.error("获取服务列表异常", e);
            return R.fail(errorMsg);
        }
    }

    /**
     * 停止服务
     * @param cangKuUuid 仓库UUID
     * @param jarName 服务包名
     * @return 操作结果
     */
    @Override
    public R stopService(String cangKuUuid, String jarName) {
        log.info("开始处理停止服务请求 - 仓库UUID: {}, 服务包名: {}", cangKuUuid, jarName);

        // 获取部署服务器信息
        List<Map<String, Object>> serverList = dispatchMapper.selectServerMessage(cangKuUuid);
        log.info("查询到服务器信息: {}", serverList);

        if (serverList.isEmpty()) {
            log.error("未找到服务器配置信息 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置服务器信息！");
        }

        Map<String, Object> serverMap = serverList.get(0);

        Object serverIpMessage = serverMap.get("chengxufuwuqiValue");
        if (StrUtil.isBlankIfStr(serverIpMessage)) {
            log.error("服务器IP地址为空 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置分发服务器ip地址！");
        }

        Object programParentFolderMessage = serverMap.get("chengxubushuwenjianjia");
        if (StrUtil.isBlankIfStr(programParentFolderMessage)) {
            log.error("程序存放路径为空 - 仓库UUID: {}", cangKuUuid);
            return R.fail("待分发程序未配置分发服务器程序存放路径！");
        }

        String serverIp = serverIpMessage.toString().split(":")[0];
        String programParentFolderPath = programParentFolderMessage.toString();
        log.info("解析服务器信息 - IP: {}, 程序路径: {}", serverIp, programParentFolderPath);

        try {
            // 1. 检查服务是否在运行
            String[] checkCmd = new String[]{
                    "ssh",
                    "-o", "BatchMode=yes",
                    "-o", "ConnectTimeout=" + SSH_TIMEOUT,
                    serverIp,
                    "ps -ef | grep " + jarName + " | grep -v grep"
            };

            log.info("执行服务状态检查命令: {}", String.join(" ", checkCmd));
            ProcessBuilder checkBuilder = new ProcessBuilder(checkCmd);
            checkBuilder.redirectErrorStream(true);
            Process checkProcess = checkBuilder.start();

            // 使用线程池执行命令，添加超时控制
            ExecutorService executor = Executors.newSingleThreadExecutor();
            StringBuilder checkOutput = new StringBuilder();
            try {
                Future<String> future = executor.submit(() -> {
                    try {
                        BufferedReader checkReader = new BufferedReader(new InputStreamReader(checkProcess.getInputStream()));
                        String line;
                        while ((line = checkReader.readLine()) != null) {
                            checkOutput.append(line).append("\n");
                        }
                        log.info("服务运行状态检查输出: {}", checkOutput);
                        if (checkOutput != null && checkOutput.toString().contains("Permission denied")) {
                            return checkOutput.toString();
                        }

                        return "ok";
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });

                // 等待命令执行完成，设置超时
                String isRunning = future.get(SSH_TIMEOUT, TimeUnit.SECONDS);
                if (!isRunning.contains("ok")) {
                    log.warn("命令执行失败: {}", isRunning);
                    return R.fail("命令执行失败: " + isRunning);
                }
                log.info("服务正在运行，准备执行停止操作。进程信息: {}", checkOutput);

            } catch (TimeoutException e) {
                log.error("服务状态检查超时", e);
                return R.fail("远程命令执行超时，请检查" + serverIp + "服务器状态或免密登录是否配置！");
            } finally {
                executor.shutdownNow();
                checkProcess.destroyForcibly();
            }

            // 2. 执行停止脚本
            String[] stopCmd = new String[]{
                    "ssh",
                    "-o", "BatchMode=yes",
                    "-o", "ConnectTimeout=" + SSH_TIMEOUT,
                    serverIp,
                    "cd " + programParentFolderPath + " && ./stop.sh " + programParentFolderPath + jarName
            };

            log.info("开始执行停止命令: {}", String.join(" ", stopCmd));
            ProcessBuilder stopBuilder = new ProcessBuilder(stopCmd);
            stopBuilder.redirectErrorStream(true);
            Process stopProcess = stopBuilder.start();

            executor = Executors.newSingleThreadExecutor();
            StringBuilder stopOutput = new StringBuilder();
            try {
                Future<Void> future = executor.submit(() -> {
                    try {
                        BufferedReader stopReader = new BufferedReader(new InputStreamReader(stopProcess.getInputStream()));
                        String line2;
                        while ((line2 = stopReader.readLine()) != null) {
                            stopOutput.append(line2).append("\n");
                        }
                        return null;
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                });

                // 等待命令执行完成，设置超时
                future.get(SSH_TIMEOUT, TimeUnit.SECONDS);
                log.info("停止脚本输出: {}", stopOutput);

            } catch (TimeoutException e) {
                log.error("停止服务命令执行超时", e);
                return R.fail("停止服务命令执行超时，请检查网络连接");
            } finally {
                executor.shutdownNow();
                stopProcess.destroyForcibly();
            }

            if (!stopProcess.waitFor(SSH_TIMEOUT, TimeUnit.SECONDS)) {
                log.error("停止脚本执行超时");
                return R.fail("停止脚本执行超时，请检查服务状态");
            }

            // 3. 验证服务是否已停止（多次尝试）
            log.info("开始验证服务状态...");

            for (int attempt = 1; attempt <= 3; attempt++) {
                log.info("第{}次验证服务状态...", attempt);
                Thread.sleep(2000);  // 每次检查间隔2秒

                String[] verifyCmd = new String[]{
                        "ssh",
                        "-o", "BatchMode=yes",
                        "-o", "ConnectTimeout=" + SSH_TIMEOUT,
                        serverIp,
                        "ps -ef | grep " + jarName + " | grep -v grep"
                };

                ProcessBuilder verifyBuilder = new ProcessBuilder(verifyCmd);
                verifyBuilder.redirectErrorStream(true);
                Process verifyProcess = verifyBuilder.start();

                executor = Executors.newSingleThreadExecutor();
                StringBuilder verifyOutput = new StringBuilder();
                boolean serviceStillRunning = false;

                try {
                    Future<Boolean> future = executor.submit(() -> {
                        try {
                            BufferedReader verifyReader = new BufferedReader(new InputStreamReader(verifyProcess.getInputStream()));
                            String line;
                            while ((line = verifyReader.readLine()) != null) {
                                verifyOutput.append(line).append("\n");
                            }
                            return verifyOutput.length() > 0;
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    });

                    serviceStillRunning = future.get(SSH_TIMEOUT, TimeUnit.SECONDS);

                    if (!serviceStillRunning) {
                        log.info("服务已确认停止");
                        return R.ok("服务已停止");
                    } else {
                        log.warn("第{}次检查：服务仍在运行，进程信息: {}", attempt, verifyOutput);
                    }

                } catch (TimeoutException e) {
                    log.error("第{}次验证服务状态超时", attempt, e);
                    if (attempt == 3) {
                        return R.fail("验证服务状态超时，请手动检查服务状态");
                    }
                } finally {
                    executor.shutdownNow();
                    verifyProcess.destroyForcibly();
                }
            }

            // 如果经过多次尝试服务仍在运行
            return R.fail("服务停止失败，服务进程仍在运行，请手动检查并停止");

        } catch (Exception e) {
            log.error("停止服务过程发生异常", e);
            return R.fail("停止服务异常：" + e.getMessage());
        }
    }

    /**
     * 服务包内部派发
     * @param cangKuUuid
     * @return
     */
    @Override
    public R dispatchInner(String cangKuUuid , String upgradePackageName) {
        List<Map<String, Object>> serverMessageList = dispatchMapper.selectServerMessage(cangKuUuid);
        if (serverMessageList.isEmpty()) {
            return R.fail("未找到服务器配置信息！");
        }
        Map<String, Object> server1Message = serverMessageList.get(0);


        if (StrUtil.isBlankIfStr(server1Message.get("shengjizu"))) {
            return R.fail("未配置升级组信息！");
        }

        String shengjizu = server1Message.get("shengjizu").toString();

//        List<Map<String , Object>> severList = dispatchMapper.selectServerByShengJiZu(shengjizu);
        List<Map<String , Object>> severList = new ArrayList<Map<String , Object>>();

        severList.add(
          new HashMap<String , Object>() {{
              put("chengxubushuwenjianjia" , "/ydTest2/");
              put("shengjibaoming" , "dist");
              put("chengxufuwuqiValue" , "172.31.242.11");
              put("banbenhao" , "20030704");
              put("chengxufuwuqiName" , "program3:80");
              put("type" , "h5");
          }}
        );



        ArrayList<Map<String , Object>> resultList = new ArrayList<>();
        log.info("分发服务器组: {}", severList);
        for (Map<String, Object> server : severList) {

            Map<String, Object> resultMap = new HashMap<>();
            resultList.add(resultMap);
            resultMap.put("cangKuUuid", server.get("cangKuUuid"));
            resultMap.put("cangKuXiangMuMingCheng", server.get("cangKuXiangMuMingCheng"));
            resultMap.put("chengxufuwuqiName", server.get("chengxufuwuqiName"));
            if (StrUtil.isBlankIfStr(server.get("chengxubushuwenjianjia"))) {
                resultMap.put("message", "未配置派发路径!");
                continue;
            }
            resultMap.put("path" , server.get("chengxubushuwenjianjia"));

            if (StrUtil.isBlankIfStr(server.get("shengjibaoming"))) {
                resultMap.put("message", "未配置升级包名!");
                continue;
            }

            if (StrUtil.isBlankIfStr(server.get("chengxufuwuqiValue"))) {
                resultMap.put("message", "未配置分发服务器地址!");
                continue;
            }

            if (StrUtil.isBlankIfStr(server.get("chengxufuwuqiValue"))) {
                resultMap.put("message", "未配置分发服务器地址!");
                continue;
            }

            if (StrUtil.isBlankIfStr(server.get("banbenhao"))) {
                resultMap.put("message", "无版本号信息!");
                continue;
            }


            if (StrUtil.isBlankIfStr(server.get("chengxufuwuqiName"))) {
                resultMap.put("message", "未配置分发服务器名称!");
                continue;
            }

            String chengxufuwuqiName = server.get("chengxufuwuqiName").toString();

            String[] chengxufuwuqiNameSplit = chengxufuwuqiName.split(":");
            if (chengxufuwuqiNameSplit.length < 2) {
                resultMap.put("message", "分发服务器名称配置错误!");
                continue;
            }

            String shengjibaoming = server.get("shengjibaoming").toString();
            String banbenhao = server.get("banbenhao").toString();


            String extension = "";
            int lastDotIndex = upgradePackageName.lastIndexOf('.');
            if (lastDotIndex > 0) {
                extension = upgradePackageName.substring(lastDotIndex + 1);
            }

            if (StrUtil.isBlankIfStr(server.get("type")) || (!"h5".equals(server.get("type")) && !"java".equals(server.get("type")) )) {
                resultMap.put("message", "未配置服务类型或服务类型不为java/h5！");
                continue;
            }


            if ("h5".equals(server.get("type"))) {
                // h5派发
                dispatchH5(upgradePackageName, server, shengjibaoming, chengxufuwuqiNameSplit, banbenhao, extension, resultMap);
            } else if ("java".equals(server.get("type"))) {
                // java派发
                dispatchJava(upgradePackageName, server, shengjibaoming, chengxufuwuqiNameSplit, banbenhao, extension, resultMap);
            }

        }

        log.info("分发任务完成，共处理 {} 个服务器，成功: {}, 失败: {}",
                resultList.size(),
                resultList.stream().mapToLong(r -> "分发成功!".equals(r.get("message")) ? 1 : 0).sum(),
                resultList.stream().mapToLong(r -> !"分发成功!".equals(r.get("message")) ? 1 : 0).sum());

        return R.ok(resultList);
    }

    private void dispatchH5(String upgradePackageName, Map<String, Object> server, String shengjibaoming, String[] chengxufuwuqiNameSplit, String banbenhao, String extension, Map<String, Object> resultMap) {
        
        // 本机ip
        String localIp = this.localIp;
        // 原始升级文件夹路径 在本机ip中
        String upgradePackageFolder = upgradePackageFolderPath  + upgradePackageName;

        // 分发主机
        String chengxufuwuqiValue = server.get("chengxufuwuqiValue").toString().split(":")[0];

        // 分发路径(父目录)
        String dispatchPath = server.get("chengxubushuwenjianjia").toString();

        // 最终文件夹名
        String dispatchPackageName = shengjibaoming;

        // 目标主机全路径
        String dispatchPathFull = dispatchPath + dispatchPackageName;

        resultMap.put("dispatchPackageName", dispatchPackageName);

        // 先检查SSH连接是否可用
        if (!checkSshConnection(chengxufuwuqiValue)) {
            log.error("SSH连接检查失败 - 服务器IP: {}", chengxufuwuqiValue);
            resultMap.put("message", "无法连接到目标服务器，请检查SSH免密配置是否正确!");
            return;
        }

        try {
            log.info("开始处理H5服务器分发 - 服务器IP: {}, 项目: {}", chengxufuwuqiValue, server.get("cangKuXiangMuMingCheng"));
            log.info("原始升级文件夹路径: {}", upgradePackageFolder);
            log.info("目标分发文件夹名: {}", dispatchPackageName);
            log.info("目标服务器路径: {}", dispatchPathFull);

            File sourceFile = new File(upgradePackageFolder);

            if (!sourceFile.exists()) {
                log.error("原始升级文件夹不存在: {}", upgradePackageFolder);
                resultMap.put("message", "原始升级包文件不存在!");
                return;
            }



            String backupPackageName = dispatchPackageName + "-" + banbenhao;
            String oldVersionPath = dispatchPath + oldVersionFolderName;
            String backupPathFull = oldVersionPath + "/" + backupPackageName;
            
            log.info("H5分发 - 将升级文件夹放入旧版本文件夹: {}", backupPathFull);
            
            // 1. 在目标服务器上创建旧版本文件夹（如果不存在）
            String mkdirCommand = String.format("ssh %s \"mkdir -p %s\"", chengxufuwuqiValue, oldVersionPath);
            log.info("执行创建旧版本目录命令: {}", mkdirCommand);
            
            Process mkdirProcess = null;
            try {
                ProcessBuilder mkdirBuilder = new ProcessBuilder();
                if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                    mkdirBuilder.command("cmd", "/c", mkdirCommand);
                } else {
                    mkdirBuilder.command("bash", "-c", mkdirCommand);
                }
                
                mkdirProcess = mkdirBuilder.start();
                int mkdirExitCode = mkdirProcess.waitFor();
                
                if (mkdirExitCode != 0) {
                    log.error("创建旧版本目录失败 - 退出码: {}", mkdirExitCode);
                    resultMap.put("message", "创建旧版本目录失败，部署中断");
                    return;
                }
                
                // 2. 将升级文件夹从本机传输到目标服务器的旧版本文件夹中
                String scpBackupCommand = String.format("scp -r %s %s:%s", 
                        upgradePackageFolder, chengxufuwuqiValue, backupPathFull);
                log.info("执行复制升级文件夹到旧版本文件夹命令: {}", scpBackupCommand);
                
                ProcessBuilder cpBuilder = new ProcessBuilder();
                if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                    cpBuilder.command("cmd", "/c", scpBackupCommand);
                } else {
                    cpBuilder.command("bash", "-c", scpBackupCommand);
                }
                
                Process cpProcess = cpBuilder.start();
                int cpExitCode = cpProcess.waitFor();
                
                if (cpExitCode == 0) {
                    log.info("升级文件夹复制到旧版本文件夹成功");
                } else {
                    log.error("升级文件夹复制到旧版本文件夹失败 - 退出码: {}", cpExitCode);
                    resultMap.put("message", "升级文件夹复制到旧版本文件夹失败，部署中断");
                    return;
                }
                
                // 3. 检查目标路径下是否存在同名文件夹，如果存在则重命名备份（倒数第二步）
                String checkCommand = String.format("ssh %s \"if [ -d %s ]; then echo 'exists'; else echo 'not_exists'; fi\"",
                        chengxufuwuqiValue, dispatchPathFull);
                log.info("检查目标路径下是否存在同名文件夹: {}", checkCommand);
                
                ProcessBuilder checkBuilder = new ProcessBuilder();
                if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                    checkBuilder.command("cmd", "/c", checkCommand);
                } else {
                    checkBuilder.command("bash", "-c", checkCommand);
                }
                
                Process checkProcess = checkBuilder.start();
                BufferedReader checkReader = new BufferedReader(new InputStreamReader(checkProcess.getInputStream()));
                String checkResult = checkReader.readLine();
                checkProcess.waitFor();
                
                if ("exists".equals(checkResult)) {
                    log.info("目标路径下存在同名文件夹，将其重命名备份: {}", dispatchPathFull);
                    
                    // 重命名目标路径下的同名文件夹（添加时间戳后缀）
                    long timestamp = System.currentTimeMillis();
                    String backupPath = dispatchPathFull + "-" + timestamp;
                    
                    String mvCommand = String.format("ssh %s \"mv %s %s\"", chengxufuwuqiValue, dispatchPathFull, backupPath);
                    log.info("执行重命名同名文件夹命令: {}", mvCommand);
                    
                    ProcessBuilder mvBuilder = new ProcessBuilder();
                    if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                        mvBuilder.command("cmd", "/c", mvCommand);
                    } else {
                        mvBuilder.command("bash", "-c", mvCommand);
                    }
                    
                    Process mvProcess = mvBuilder.start();
                    int mvExitCode = mvProcess.waitFor();
                    
                    if (mvExitCode == 0) {
                        log.info("同名文件夹重命名成功，备份路径: {}", backupPath);
                    } else {
                        log.error("同名文件夹重命名失败 - 退出码: {}", mvExitCode);
                        resultMap.put("message", "同名文件夹重命名失败，部署中断");
                        return;
                    }
                } else {
                    log.info("目标路径下不存在同名文件夹，无需重命名");
                }
                
            } catch (Exception e) {
                log.error("处理旧版本过程发生异常: {}", e.getMessage(), e);
                resultMap.put("message", "处理旧版本过程发生异常: " + e.getMessage());
                return;
            }

            // 4. 使用SCP命令将升级文件夹分发到目标路径，名字为shengjibaoming（最后一步）
            String scpCommand = String.format("scp -r %s %s:%s", upgradePackageFolder, chengxufuwuqiValue, dispatchPathFull);
            log.info("执行SCP命令将升级文件夹分发到目标路径: {}", scpCommand);

            ProcessBuilder processBuilder = new ProcessBuilder();
            if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                processBuilder.command("cmd", "/c", scpCommand);
            } else {
                processBuilder.command("bash", "-c", scpCommand);
            }

            Process process = processBuilder.start();

            // 读取命令输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            String line;
            StringBuilder output = new StringBuilder();
            StringBuilder errorOutput = new StringBuilder();

            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }

            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
            }

            // 等待命令执行完成
            int exitCode = process.waitFor();
            log.info("SCP命令执行完成，退出码: {}", exitCode);

            if (output.length() > 0) {
                log.info("SCP输出: {}", output.toString().trim());
            }

            if (errorOutput.length() > 0) {
                log.warn("SCP错误输出: {}", errorOutput.toString().trim());
            }

            if (exitCode == 0) {
                log.info("文件分发成功 - 服务器: {}, 包名: {}", chengxufuwuqiValue, dispatchPackageName);
                resultMap.put("message", "分发成功!");
            } else {
                log.error("文件分发失败 - 服务器: {}, 退出码: {}, 错误信息: {}",
                        chengxufuwuqiValue, exitCode, errorOutput.toString().trim());
                resultMap.put("message", "分发失败: " + errorOutput.toString().trim());
            }

        } catch (IOException e) {
            log.error("文件操作异常 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "文件操作失败: " + e.getMessage());
        } catch (InterruptedException e) {
            log.error("命令执行被中断 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "命令执行被中断: " + e.getMessage());
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            log.error("分发过程发生未知异常 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "分发失败: " + e.getMessage());
        }

    }


    private void dispatchJava(String upgradePackageName, Map<String, Object> server, String shengjibaoming, String[] chengxufuwuqiNameSplit, String banbenhao, String extension, Map<String, Object> resultMap) {
        // 原始升级包全路径
        String upgradePackagePath = upgradePackageFolderPath  + upgradePackageName;

        // 分发主机
        String chengxufuwuqiValue = server.get("chengxufuwuqiValue").toString().split(":")[0];

        // 分发路径(父目录)
        String dispatchPath = server.get("chengxubushuwenjianjia").toString();

        // 分发包名
        String dispatchPackageName = shengjibaoming + "-" + chengxufuwuqiNameSplit[1] + "-" + banbenhao + "." + extension;

        // 目标主机全路径
        String dispatchPathFull = dispatchPath + dispatchPackageName;


        resultMap.put("dispatchPackageName", dispatchPackageName);


        // 先检查SSH连接是否可用
        if (!checkSshConnection(chengxufuwuqiValue)) {
            log.error("SSH连接检查失败 - 服务器IP: {}", chengxufuwuqiValue);
            resultMap.put("message", "无法连接到目标服务器，请检查SSH免密配置是否正确!");
            return;
        }

        try {
            log.info("开始处理服务器分发 - 服务器IP: {}, 项目: {}", chengxufuwuqiValue, server.get("cangKuXiangMuMingCheng"));
            log.info("原始升级包路径: {}", upgradePackagePath);
            log.info("目标分发包名: {}", dispatchPackageName);
            log.info("目标服务器路径: {}", dispatchPathFull);

            // 1. 创建临时目录（如果不存在）
            File tempDir = new File(dispatchTempPath);
            if (!tempDir.exists()) {
                boolean created = tempDir.mkdirs();
                log.info("创建临时目录: {} - {}", dispatchTempPath, created ? "成功" : "失败");
            }

            // 2. 复制并重命名升级包到临时目录
            String tempPackagePath = dispatchTempPath + dispatchPackageName;
            File sourceFile = new File(upgradePackagePath);
            File targetFile = new File(tempPackagePath);

            if (!sourceFile.exists()) {
                log.error("原始升级包文件不存在: {}", upgradePackagePath);
                resultMap.put("message", "原始升级包文件不存在!");
                return;
            }

            log.info("复制升级包: {} -> {}", upgradePackagePath, tempPackagePath);
            Files.copy(sourceFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
            log.info("升级包复制完成，文件大小: {} bytes", targetFile.length());

            // 3. 使用SCP命令分发到目标服务器
            String scpCommand = String.format("scp %s %s:%s", tempPackagePath, chengxufuwuqiValue, dispatchPathFull);
            log.info("执行SCP命令: {}", scpCommand);

            ProcessBuilder processBuilder = new ProcessBuilder();
            if (System.getProperty("os.name").toLowerCase().contains("windows")) {
                processBuilder.command("cmd", "/c", scpCommand);
            } else {
                processBuilder.command("bash", "-c", scpCommand);
            }

            Process process = processBuilder.start();

            // 读取命令输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));

            String line;
            StringBuilder output = new StringBuilder();
            StringBuilder errorOutput = new StringBuilder();

            while ((line = reader.readLine()) != null) {
                output.append(line).append("\n");
            }

            while ((line = errorReader.readLine()) != null) {
                errorOutput.append(line).append("\n");
            }

            // 等待命令执行完成
            int exitCode = process.waitFor();
            log.info("SCP命令执行完成，退出码: {}", exitCode);

            if (output.length() > 0) {
                log.info("SCP输出: {}", output.toString().trim());
            }

            if (errorOutput.length() > 0) {
                log.warn("SCP错误输出: {}", errorOutput.toString().trim());
            }

            if (exitCode == 0) {
                log.info("文件分发成功 - 服务器: {}, 包名: {}", chengxufuwuqiValue, dispatchPackageName);
                resultMap.put("message", "分发成功!");
            } else {
                log.error("文件分发失败 - 服务器: {}, 退出码: {}, 错误信息: {}",
                        chengxufuwuqiValue, exitCode, errorOutput.toString().trim());
                resultMap.put("message", "分发失败: " + errorOutput.toString().trim());
            }

            // 无论分发成功或失败都删除临时文件
            if (targetFile.delete()) {
                log.info("临时文件删除成功: {}", tempPackagePath);
            } else {
                log.warn("临时文件删除失败: {}", tempPackagePath);
            }

        } catch (IOException e) {
            log.error("文件操作异常 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "文件操作失败: " + e.getMessage());
        } catch (InterruptedException e) {
            log.error("命令执行被中断 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "命令执行被中断: " + e.getMessage());
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            log.error("分发过程发生未知异常 - 服务器: {}, 异常信息: {}", chengxufuwuqiValue, e.getMessage(), e);
            resultMap.put("message", "分发失败: " + e.getMessage());
        }
    }



    @Override
    public R upgradeList(String cangKuUuid) {
        HashMap<String, Object> resultMap = new HashMap<>();

        List<Map<String, Object>> serverMessageList = dispatchMapper.selectServerMessage(cangKuUuid);
        if (serverMessageList.isEmpty()) {
            return R.fail("未找到服务器配置信息！");
        }
        Map<String, Object> server1Message = serverMessageList.get(0);


        if (StrUtil.isBlankIfStr(server1Message.get("shengjizu"))) {
            return R.fail("未配置升级组信息！");
        }

        String shengjizu = server1Message.get("shengjizu").toString();

//        List<Map<String , Object>> severList = dispatchMapper.selectServerByShengJiZu(shengjizu);

        List<Map<String , Object>> severList = new ArrayList<Map<String , Object>>();

        severList.add(
                new HashMap<String , Object>() {{
                    put("chengxubushuwenjianjia" , "/ydTest2/");
                    put("shengjibaoming" , "dist");
                    put("chengxufuwuqiValue" , "172.31.242.11");
                    put("banbenhao" , "20030704");
                    put("chengxufuwuqiName" , "program3:80");
                    put("type" , "h5");
                }}
        );

        ArrayList<Map<String, Object>> resultList = new ArrayList<>();

        try {
            // 1、查询本机 upgradePackageFolderPath 下的所有文件和文件夹列表
            File upgradeDir = new File(upgradePackageFolderPath);
            if (!upgradeDir.exists()) {
                log.warn("升级包目录不存在: {}", upgradePackageFolderPath);
            } else if (!upgradeDir.isDirectory()) {
                log.warn("升级包路径不是目录: {}", upgradePackageFolderPath);
            } else {
                File[] files = upgradeDir.listFiles();
                if (files != null) {
                    // 2、把结果填充到 resultList 中
                    for (File file : files) {
                        Map<String, Object> fileInfo = new HashMap<>();
                        fileInfo.put("name", file.getName());
                        fileInfo.put("type", file.isDirectory() ? "文件夹" : "文件");

                        // 文件的话有最后修改时间
                        if (file.isFile()) {
                            long lastModified = file.lastModified();
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            long fileSizeBytes = file.length();
                            double fileSizeMB = fileSizeBytes / (1024.0 * 1024.0);

                            fileInfo.put("lastModified", lastModified);
                            fileInfo.put("lastModifiedTime", sdf.format(new java.util.Date(lastModified)));
                            fileInfo.put("size", String.format("%.2f MB", fileSizeMB));
                            fileInfo.put("sizeBytes", fileSizeBytes); // 保留原始字节数用于排序
                        } else {
                            fileInfo.put("lastModified", 0L);
                            fileInfo.put("lastModifiedTime", null);
                            fileInfo.put("size", "0.00 MB");
                            fileInfo.put("sizeBytes", 0L);
                        }

                        resultList.add(fileInfo);
                    }

                    // 按文件最后修改时间倒序排序（文件夹排在后面）
                    resultList.sort((a, b) -> {
                        Long timeA = (Long) a.get("lastModified");
                        Long timeB = (Long) b.get("lastModified");
                        return Long.compare(timeB, timeA);
                    });
                }
            }
        } catch (Exception e) {
            log.error("获取升级包列表失败", e);
        }

        resultMap.put("severList" , severList);
        resultMap.put("upgradePackageList" , resultList);

        return R.ok(resultMap);
    }


}
